#include "lib.h"

#include "vpgame.h"
#include "vpconn.h"
#include "shue.h"
#include "vphand.h"
#include "vpguts.h"
#include "vpsaved.h"
#include "GameDBInterface.h"
#include "VPSQL.h"

//constructor used for new games
VPGame::VPGame(VPConnection* conn, GameDBInterface *pDBInterface)
{    
    this->conn = conn;
    m_pDBInterface = (VPokerSQL *) pDBInterface;
    this->bet = 0;
    this->dblUpEnabled = conn->getDoubleUpEnabled();
	this->dlbUpCapAmount = conn->getDoubleUpCapAmount();
    guts = VPGuts::getGuts(conn->getMachId(), conn->getPayTableFreq());

	sgi.gameId = conn->getGameID();
	sgi.machId = conn->getMachId();

     #ifdef FORCEDSHOE 
       sgi.pid=conn->GetPID();
    #endif


    shue = guts->newShue(sgi);

    if (shue)
        shue->shuffle();
    hand = new VPHand(guts->getCardMgr());
    state = VPGS_NOTSTARTED;
    dblUpPayout = 0;
    dblUpPayType = 0xff;
    dblUpRound = 0;
    dblUpWon = 0;
    restoreOrigPayType = 0xff;        // only used to temporarily hold
    restoreLastHeld = 0;            //    info to help restore the client
}

//constructor used for saved games
VPGame::VPGame(VPConnection* conn, GameDBInterface *pDBInterface, VPokerSavedGame* saved)
{
    this->conn = conn;
    m_pDBInterface = (VPokerSQL *) pDBInterface;
	dlbUpCapAmount = conn->getDoubleUpCapAmount();

    // everything else is restored in restore()
    //
    bet = 0;
    shue = (Shue*)0;
    guts = (VPGuts*)0;
    hand = (VPHand*)0;
    state = VPGS_GAMEOVER;
    dblUpEnabled = false;
    dblUpPayout = 0;
    dblUpPayType = 0xff;
    dblUpRound = 0;
    dblUpWon = 0;
    restoreOrigPayType = 0xff;        // only used to temporarily hold
    restoreLastHeld = 0;            //    info to help restore the client

    if (!restore(saved))
    {
        delete shue;
        delete hand;
        shue = (Shue*)0;
        hand = (VPHand*)0;
        guts = (VPGuts*)0;
        state = VPGS_GAMEOVER;
    }
}

VPGame::~VPGame()
{
    delete shue;
    delete hand;
    guts = (VPGuts*)0;
}

bool8
VPGame::initOk()
{
    if (state == VPGS_NOTSTARTED ||
        state == VPGS_GAMESTARTED ||
        state == (VPGS_GAMESTARTED | VPGS_DBLUPSTARTED))
        return (bool8)(
            guts != (VPGuts*)0 &&
            shue != (Shue*)0 &&
            hand != (VPHand*)0);
    else if (state == (VPGS_GAMESTARTED | VPGS_DBLUPPENDING))
        return (bool8)(
            guts != (VPGuts*)0 &&
            shue == (Shue*)0 &&
            hand != (VPHand*)0);    // hand will be destroyed in restore()
    else
        return false;
}

int32
VPGame::getPayFreq()
{
    return guts->getPayFreq();
}

int32
VPGame::deal()
{
    int32 result = DEAL_CREATE_GAME_FAILURE;

    if (state == VPGS_NOTSTARTED)
    {
        // Start the game here validating everything that doesn't require
        // SQL data.  Attempt to create and save the game state in SQL (create
        // the game and save the dealt hands, create a save game, adjust
        // the balance) and validate the rest there. 
        //
        // Any failure will rollback all changes (both in SQL and within the
        // game).
        // 
        if (bet > 0 && bet <= conn->getMaxBet())
        {
            int32            paytype, balance;
            VPHand            clientVisibleHand(guts->getCardMgr());
            VPokerSavedGame    savedGame;

            guts->dealHand(shue, hand);

            //patrick 06/28/02: added sub game member to create game specific information to the client
            guts->createSubGameData(conn->getSubGameData(), conn->getSubGameLengthByRef(), VPConnection::MAX_SUBGAME_DATA);
            
            guts->CalcPayout(&paytype, hand, bet, VPGuts::DEALT_CARDS, conn->getSubGameData(), conn->getSubGameLength());

            guts->makeDealtHandForClient(hand, &clientVisibleHand);

            save(&savedGame);
			
			result = m_pDBInterface->trackNewGame(
				conn->creditsToCents(bet),
				&clientVisibleHand,
				&savedGame,
				&balance);

			m_pDBInterface->trackNewSubGame();

            if (result == VPGameBase::NG_OK)
            {
                state = VPGS_GAMESTARTED;

                conn->msgStart();
                conn->msgAdd((uint8)'D');

                if(conn->getProtocolVersion1()>=2)
                {
                    // kharmon.  03-22-06.  #10515.  Newer clients expect to get the number of cards.
                    conn->msgAdd((uint8)(clientVisibleHand.getCount() & 0xFF));
                }

                conn->msgReleaseBuf(clientVisibleHand.out(conn->msgGetBuf()));
                conn->msgAdd((uint8)(paytype & 0xFF));
                conn->msgAdd(balance);
                conn->msgEnd();

                uint8* subdata = conn->getSubGameData();
                int32 length = conn->getSubGameLength();
                if (length > 0)
                {
                    conn->msgStart();    //subgame data
                    conn->msgAdd((uint8)'S');
                    for(int32 i=0;i<length;i++)
                    {
                        conn->msgAdd(subdata[i]);
                    }
                    conn->msgEnd();
                }

                result = DEAL_SUCCESS;
            }
            else
            {
                switch (result)
                {
                    case VPGameBase::NG_NOMONEY:
                        result = DEAL_NOT_ENOUGH_MONEY;
                        break;

                    default:
                        result = DEAL_CREATE_GAME_FAILURE;
                        break;
                }

                // roll back server (SQL has already been rolled back)
                //
                guts->rollbackDeal(shue, hand);
            }
        }
        else
            result = DEAL_INVALID_BET;
    }

    return result;
}

int32
VPGame::holdThese(uint8 Cards)
{
    int32 result = HOLD_FAILURE;

    if (state == VPGS_GAMESTARTED)
    {
        // Continue the game here validating everything that doesn't require
        // SQL data.  Attempt to update the game state in SQL (save drawn
        // hands, remove the saved game, adjust the balance) and validate the
        // rest there. 
        //
        // Any failure will rollback all changes (both in SQL and within the
        // game).
        // 
        if (guts->isHoldTheseValid(Cards))
        {
            int32    payout, paytype, balance;
            VPHand    clientVisibleHand(guts->getCardMgr());

            guts->drawHand(Cards, shue, hand);

            payout = guts->CalcPayout(&paytype, hand, bet, VPGuts::DRAWN_CARDS, conn->getSubGameData(), conn->getSubGameLength());

            guts->makeDrawnHandForClient(hand, &clientVisibleHand);    

            dblUpPayout = payout;
            dblUpPayType = paytype;
            dblUpRound = 0;
            dblUpWon = 0;

			//psharpless 10/20/06
			//Case: 11052  New Double Up Win Cap Logic
            if (payout && dblUpEnabled && 
				conn->creditsToCents(payout) <= dlbUpCapAmount)
			{
                state |= VPGS_DBLUPPENDING;
			}

            if (m_pDBInterface->trackDraw(
                &clientVisibleHand,
                conn->creditsToCents(payout),
                paytype,
                (bool8)((state & VPGS_DBLUPPENDING) != 0),
                &balance))
            {
                delete shue;
                delete hand;
                shue = (Shue*)0;
                hand = (VPHand*)0;

                if ((state & VPGS_DBLUPPENDING) == 0)
                    state = VPGS_GAMEOVER;

                conn->msgStart();
                conn->msgAdd((uint8)'H');
                conn->msgReleaseBuf(clientVisibleHand.out(conn->msgGetBuf()));
                conn->msgAdd((uint8)(paytype & 0xFF));
                conn->msgAdd(payout);
                conn->msgAdd((uint8)((state & VPGS_DBLUPPENDING) != 0));
                conn->msgAdd((uint8)(dblUpPayType & 0xFF));
                conn->msgAdd((uint8)(dblUpWon & 0xFF));
                conn->msgAdd(dblUpPayout);
                conn->msgAdd(balance);
                conn->msgEnd();

                result = (state == VPGS_GAMEOVER
                    ? HOLD_SUCCESS_GAMEOVER
                    : HOLD_SUCCESS_DBLUP_PENDING);
            }
            else
            {
                // roll back server (SQL has already been rolled back)
                //
                guts->rollbackDraw(Cards, shue, hand);
                state &= ~VPGS_DBLUPPENDING;

                ASSERT(state == VPGS_GAMESTARTED);
            }
        }
    }

    return result;
}

bool8
VPGame::doubleUpDeny()
{
    bool8 result = false;

    if (state & VPGS_DBLUPPENDING)
    {
        int32 balance;

        if (m_pDBInterface->trackDoubleUpDeny(
            conn->creditsToCents(dblUpPayout),
            &balance))
        {
            state = VPGS_GAMEOVER;

            conn->msgStart();
            conn->msgAdd((uint8)'X');
            conn->msgAdd((uint8)(dblUpPayType & 0xFF));
            conn->msgAdd(dblUpPayout);
            conn->msgAdd(balance);
            conn->msgEnd();

            result = true;
        }
        //
        // upon failure, everything already rolled-back
        //
    }

    return result;
}

bool8
VPGame::doubleUpDeal()
{
    bool8 result = false;

    if (state & VPGS_DBLUPPENDING)
    {
        shue = guts->newShue(sgi);
        hand = new VPHand(guts->getCardMgr());

        if (shue && hand)
        {
            ShueSave shueSave;
            int32 balance;

            shue->shuffle();
            hand->add(shue->getCard());

            shue->save(&shueSave);

            if (m_pDBInterface->trackDoubleUpDeal(
                dblUpRound,
                hand->getCardAt(0),
                &shueSave,
                &balance))
            {
                state &= ~VPGS_DBLUPPENDING;
                state |= VPGS_DBLUPSTARTED;

                conn->msgStart();
                conn->msgAdd((uint8)'U');
                conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));
                conn->msgAdd(balance);
                conn->msgEnd();

                result = true;
            }
        }

        //
        // upon failure, rollback
        //
        if (!result)
        {
            delete shue;
            delete hand;
            shue = (Shue*)0;
            hand = (VPHand*)0;
        }
    }

    return result;
}

int32
VPGame::doubleUpDraw(uint8 held)
{
    int32 result = DUDRAW_FAILURE;

    if ((state & VPGS_DBLUPSTARTED) != 0 && held >= 1 && held < 5)
    {
        int32 newDblUpPayout, newDblUpPayType, newDblUpRound, newDblUpWon;
        int32 winner;
        int32 newState;
        int32 balance;

        hand->add(shue->getCard());
        hand->add(shue->getCard());
        hand->add(shue->getCard());
        hand->add(shue->getCard());

        winner = guts->doubleUpCompare(
            hand->getCardAt(0),
            hand->getCardAt(held));

        if (winner > 0)
        {
            newDblUpPayout = 0;                        // house wins
            newDblUpPayType = VPEVT_DBLUP_LOSER;
            newDblUpRound = 0;
            newDblUpWon = 0;
            newState = VPGS_GAMEOVER;
        }
        else if (winner < 0)
        {
            newDblUpPayout = dblUpPayout << 1;        // player wins
            newDblUpPayType = VPEVT_DBLUP_WON;
            newDblUpRound = dblUpRound + 1;
            newDblUpWon = dblUpWon + 1;
            newState = state & ~VPGS_DBLUPSTARTED;

			//psharpless 10/20/06
			//Case: 11052  New Double Up Win Cap Logic
			if(conn->creditsToCents(newDblUpPayout) <= dlbUpCapAmount)
			{
				newState = newState | VPGS_DBLUPPENDING;
			}
        }
        else
        {
            newDblUpPayout = dblUpPayout;            // tie
            newDblUpPayType = VPEVT_DBLUP_TIE;
            newDblUpRound = dblUpRound + 1;
            newDblUpWon = dblUpWon;
            newState = (state & ~VPGS_DBLUPSTARTED) | VPGS_DBLUPPENDING;
        }

        if (m_pDBInterface->trackDoubleUpDraw(dblUpRound,
            hand->getCardAt(held),
            winner,
            conn->creditsToCents(newDblUpPayout),
            &balance))
        {
            dblUpPayout = newDblUpPayout;
            dblUpPayType = newDblUpPayType;
            dblUpRound = newDblUpRound;
            dblUpWon = newDblUpWon;
            state = newState;

            conn->msgStart();
            conn->msgAdd((uint8)'u');

            if(conn->getProtocolVersion1()>=2)
            {
                // kharmon.  03-22-06.  #10515.  Newer clients expect to get the number of cards.
                conn->msgAdd((uint8)(hand->getCount() & 0xFF));
            }

            conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));
            conn->msgAdd((uint8)((state & VPGS_DBLUPPENDING) != 0));
            conn->msgAdd((uint8)(dblUpPayType & 0xFF));
            conn->msgAdd((uint8)(dblUpWon & 0xFF));
            conn->msgAdd(dblUpPayout);
            conn->msgAdd(balance);
            conn->msgEnd();

            delete shue;
            delete hand;
            shue = (Shue*)0;
            hand = (VPHand*)0;

			//psharpless 10/20/06
			//Case: 11052  New Double Up Win Cap Logic

			//we just won a double up, but another double up is not pending, 
			//we must have hit the cap so update the users balance with their winnings
			if(dblUpWon && !(state & VPGS_DBLUPPENDING))
			{
				m_pDBInterface->trackDoubleUpDeny(conn->creditsToCents(dblUpPayout),&balance);
			}

            result = (state & VPGS_DBLUPPENDING
                ? DUDRAW_SUCCESS_DBLUP_PENDING
                : DUDRAW_SUCCESS_GAMEOVER);
        }
        else
        {
            // roll back server (SQL has already been rolled back)
            //
            shue->pushBackNCards(4);
            hand->removeAt(4);
            hand->removeAt(3);
            hand->removeAt(2);
            hand->removeAt(1);
        }
    }

    return result;
}

void 
VPGame::save(VPokerSavedGame* saved)
{
    shue->save(&saved->shue);
    saved->bet = conn->creditsToCents(bet);
    saved->payFreq = guts->getPayFreq();
    saved->dblUpEnabled = dblUpEnabled;
    //
    // the rest is already stored in the database
    //
}

bool8 
VPGame::restore(VPokerSavedGame* saved)
{
    bool8 result = false;

	sgi.gameId = conn->getGameID();
	sgi.machId = conn->getMachId();

    switch (saved->kind)
    {
        case VPokerSavedGame::VPOKER_PLAYING:
            guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
            if (guts)
            {
                shue = guts->newShue(sgi);
                if (shue)
                {
                    shue->restore(&saved->shue);

                    hand = new VPHand(guts->getCardMgr());
                    if (hand)
                    {
                        guts->restoreHand(shue, hand, saved);
                        bet = conn->centsToCredits(saved->bet);
                        dblUpEnabled = saved->dblUpEnabled;

                        state = VPGS_GAMESTARTED;

                        result = true;
                    }
                }
            }
            break;

        case VPokerSavedGame::DBLUP_AVAIL_1ST:
            guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
            if (guts)
            {
                ASSERT(shue == (Shue*)0);

                // This hand holds the results of the final vpoker game;
                // it is only kept around long enough to send to the client
                // and then it is destroyed in VPGame::send().
                // (it shouldn't exist in the server at this state in the game).
                //
                hand = new VPHand(guts->getCardMgr());
                if (hand)
                {
                    hand->restore(saved->cards, VPokerSavedGame::MAXCARDS);

                    bet = conn->centsToCredits(saved->bet);
                    dblUpEnabled = saved->dblUpEnabled;
                    dblUpPayout = conn->centsToCredits(saved->dblUpPayout);
                    dblUpPayType = saved->dblUpPayType;
                    dblUpRound = saved->dblUpRound;
                    dblUpWon = saved->dblUpWins;
                    restoreOrigPayType = saved->dblUpOrigPayType;
                    restoreLastHeld = guts->restoreHeldCards(
                        saved->dblUpLastDealt, saved->cards,
                        VPokerSavedGame::MAXCARDS);
                                
                    state = VPGS_GAMESTARTED | VPGS_DBLUPPENDING;

                    result = true;
                }
            }
            break;

        case VPokerSavedGame::DBLUP_AVAIL_NOT1ST:
            guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
            if (guts)
            {
                shue = guts->newShue(sgi);
                if (shue)
                {
                    shue->restore(&saved->shue);

                    // This hand holds the results of the final vpoker game;
                    // it is only kept around long enough to send to the client
                    // and then it is destroyed in VPGame::send().
                    // (it shouldn't exist in the server at this state in the
                    // game).
                    //
                    hand = new VPHand(guts->getCardMgr());
                    if (hand)
                    {
                        int32 i;

                        hand->add(shue->getCard());
                        hand->add(shue->getCard());
                        hand->add(shue->getCard());
                        hand->add(shue->getCard());
                        hand->add(shue->getCard());

                        delete shue;
                        shue = (Shue*)0;

                        ASSERT(hand->getCardAt(0) == saved->cards[0]);

                        restoreLastHeld = 0;
                        for (i = 1; i < 5; i++)
                        {
                            if (hand->getCardAt(i) == saved->cards[1])
                            {
                                restoreLastHeld = (uint8)(i & 0xFF);
                                break;
                            }
                        }

                        ASSERT(restoreLastHeld > 0 &&
                            restoreLastHeld < 5 &&
                            (saved->dblUpLastOutcome == 'W' ||
                                saved->dblUpLastOutcome == 'T'));

                        bet = conn->centsToCredits(saved->bet);
                        dblUpEnabled = saved->dblUpEnabled;
                        dblUpPayout = conn->centsToCredits(saved->dblUpPayout);
                        dblUpPayType =
                            saved->dblUpLastOutcome == 'W'
                                ? VPEVT_DBLUP_WON
                                : VPEVT_DBLUP_TIE;
                        dblUpRound = saved->dblUpRound;
                        dblUpWon = saved->dblUpWins;
                        restoreOrigPayType = saved->dblUpOrigPayType;

                        state = VPGS_GAMESTARTED | VPGS_DBLUPPENDING;

                        result = true;
                    }
                }
            }
            break;

        case VPokerSavedGame::DBLUP_PLAYING:
            guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
            if (guts)
            {
                shue = guts->newShue(sgi);
                if (shue)
                {
                    shue->restore(&saved->shue);

                    hand = new VPHand(guts->getCardMgr());
                    if (hand)
                    {
                        hand->add(shue->getCard());

                        ASSERT(hand->getCardAt(0) == saved->cards[0]);

                        if (saved->dblUpRound == 0)
                            dblUpPayType = saved->dblUpOrigPayType;
                        else
                        {
                            ASSERT(saved->dblUpLastOutcome == 'W' ||
                                saved->dblUpLastOutcome == 'T');

                            dblUpPayType =
                                saved->dblUpLastOutcome == 'W'
                                    ? VPEVT_DBLUP_WON
                                    : VPEVT_DBLUP_TIE;
                        }

                        bet = conn->centsToCredits(saved->bet);
                        dblUpEnabled = saved->dblUpEnabled;
                        dblUpPayout = conn->centsToCredits(saved->dblUpPayout);
                        dblUpRound = saved->dblUpRound;
                        dblUpWon = saved->dblUpWins;
                        restoreOrigPayType = saved->dblUpOrigPayType;

                        state = VPGS_GAMESTARTED | VPGS_DBLUPSTARTED;

                        result = true;
                    }
                }
            }
            break;

        default:
            break;
    }
    //
    // At this point the server is *exactly* the same as when the game was
    // saved:  all automatic playing had already completed and the game
    // was idle.
    //
    m_pDBInterface->trackGetSubGame();
    guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
    guts->restoreSubGameData(conn->getSubGameData(), conn->getSubGameLengthByRef());

    return result;
}

void 
VPGame::send()
{
    //
    // This message is contained within another message
    // (don't call msgStart()/msgEnd()).
    //
    if (state == VPGS_GAMESTARTED)
    {
        VPHand    clientVisibleHand(guts->getCardMgr());
        int32    paytype;

        guts->CalcPayout(&paytype, hand, bet, VPGuts::DEALT_CARDS, conn->getSubGameData(), conn->getSubGameLength());
        guts->makeDealtHandForClient(hand, &clientVisibleHand);

        conn->msgAdd((uint8)0x00);    // restore vpoker game
        conn->msgAdd((uint8)(guts->getPayFreq() & 0xFFL));
        conn->msgAdd(bet);
        conn->msgAdd((uint8)(paytype & 0xFF));
        conn->msgReleaseBuf(clientVisibleHand.out(conn->msgGetBuf()));
    }
    else if (state == (VPGS_GAMESTARTED | VPGS_DBLUPPENDING))
    {
        ASSERT(hand != (VPHand*)0);

        conn->msgAdd((uint8)0x01);    // restore dblup pending
        conn->msgAdd((uint8)(guts->getPayFreq() & 0xFFL));
        conn->msgAdd(bet);
        conn->msgAdd((uint8)(restoreOrigPayType & 0xFF));
        conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));
        conn->msgAdd((uint8)(restoreLastHeld & 0xFF));
        conn->msgAdd((uint8)(dblUpPayType & 0xFF));
        conn->msgAdd((uint8)(dblUpWon & 0xFF));
        conn->msgAdd(dblUpPayout);

        delete hand;        // as promised :)
        hand = (VPHand*)0;

        restoreOrigPayType = 0xff;
        restoreLastHeld = 0;
    }
    else if (state == (VPGS_GAMESTARTED | VPGS_DBLUPSTARTED))
    {
        conn->msgAdd((uint8)0x02);    // restore dblup started
        conn->msgAdd((uint8)(guts->getPayFreq() & 0xFFL));
        conn->msgAdd(bet);
        conn->msgAdd((uint8)(restoreOrigPayType & 0xFF));
        conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));
        conn->msgAdd((uint8)(dblUpPayType & 0xFF));
        conn->msgAdd((uint8)(dblUpWon & 0xFF));
        conn->msgAdd(dblUpPayout);

        restoreOrigPayType = 0xff;
    }
    else
        ASSERT(0);
}

///////////////////////////////////////////////////////////////////////////////////////
/// kharmon.  03-22-06.  #10515.
/// 
/// @fn     VPGame::handleMessage(unsigned char *pucMsgBuf, int32 nMsgLen)
/// 
/// This method examines incoming messages to see if they're of interest to the current
/// game instance.  If so, the messages are processed and appropriate responses
/// are generated by the game object.
///
/// @param  pucMsgBuf  -    (in) pointer to the raw message data.
/// @param  nMsgLen    -    (in) size of the incoming message
bool8 VPGame::handleMessage(unsigned char *pucMsgBuf, int32 nMsgLen)
{
    bool8 bRetVal = true;

    switch (pucMsgBuf[0])
    {
        case 'D':   // deal 
        {
			// [AO 2008-02-13] trackValidateSession() handled in connection

            bet = (((int32) pucMsgBuf[1])     & 0xFF)   +
                  (((int32) pucMsgBuf[2]<<8)  & 0xFF00) +
                  (((int32) pucMsgBuf[3]<<16) & 0xFF0000);


            int32 nResult = deal();

            if (nResult != VPGame::DEAL_SUCCESS)
            {
                switch (nResult)
                {
                    case VPGameBase::DEAL_INVALID_BET:
                        conn->Answer('B');
                        break;

                    case VPGameBase::DEAL_NOT_ENOUGH_MONEY:
                        conn->Answer('$');
                        break;

                    case VPGameBase::DEAL_CREATE_GAME_FAILURE:
						conn->Answer('N');
                        break;
                }

                conn->gameOver();
            }

            break;
        }

        case 'H':    // Hold
        {
            int32 nResult = holdThese(pucMsgBuf[1]);

            switch (nResult)
            {
                case VPGame::HOLD_SUCCESS_GAMEOVER:
                    conn->gameOver();
                    break;

                case VPGame::HOLD_SUCCESS_DBLUP_PENDING:
                    break;

                case VPGame::HOLD_FAILURE:
                default:
                    conn->Answer('N');
                    break;
            }

            break;
        }

        case 'X':    // deny double-up
        {
            if(doubleUpDeny())
            {
                conn->gameOver();
            }
            break;
        }

        case 'U':    // double-up deal
        {
            if(!doubleUpDeal())
            {
                conn->Answer('N');
            }
            break;
        }

        case 'u':    // double-up draw
        {
            int32 nResult = doubleUpDraw(pucMsgBuf[1]);    // creates result msg

            switch (nResult)
            {
                case VPGame::DUDRAW_SUCCESS_GAMEOVER:
                    conn->gameOver();
                    break;

                case VPGame::DUDRAW_SUCCESS_DBLUP_PENDING:
                    //
                    // game in progress; results already sent
                    //
                    break;

                case VPGame::DUDRAW_FAILURE:
                default:
                    conn->Answer('N');
                    break;
            }
            break;
        }
        default:
        {
            bRetVal = false;
            break;
        }
    }

    return bRetVal;
}
